import hashlib
import traceback

from django.shortcuts import get_object_or_404
from rest_framework.decorators import action
from rest_framework.pagination import PageNumberPagination
from rest_framework.permissions import BasePermission
from rest_framework import serializers
from rest_framework import filters
from django_filters import rest_framework
from rest_framework.viewsets import ModelViewSet
from rest_framework_jwt.authentication import JSONWebTokenAuthentication
from rest_framework.permissions import IsAuthenticated
from TemplateChaceAdmin.basic import CCAIResponse
from rest_framework.generics import ListAPIView
from rest_framework.views import exception_handler
from errno import errorcode
import logging, redis
from django.conf import settings

from TemplateChaceAdmin.code import *

error_logger = logging.getLogger("error")
info_logger = logging.getLogger("info")


class CustomViewBase(ModelViewSet):
    # pagination_class = LargeResultsSetPagination
    # filter_class = ServerFilter
    queryset = ''
    serializer_class = ''
    permission_classes = ()
    filter_fields = ()
    search_fields = ()
    filter_backends = (rest_framework.DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter,)

    def create(self, request, *args, **kwargs):
        data = req_operate_by_user(request)
        serializer = self.get_serializer(data=data)
        serializer.is_valid(raise_exception=True)
        self.perform_create(serializer)
        # headers = self.get_success_headers(serializer.data)
        return CCAIResponse(data="success")

    def list(self, request, *args, **kwargs):
        queryset = self.filter_queryset(self.get_queryset())
        page = self.paginate_queryset(queryset)
        if page is not None:
            serializer = self.get_serializer(page, many=True)
            return self.get_paginated_response(serializer.data)

        serializer = self.get_serializer(queryset, many=True)
        return CCAIResponse(data=serializer.data)

    def retrieve(self, request, *args, **kwargs):
        instance = self.get_object()
        serializer = self.get_serializer(instance)
        return CCAIResponse(data=serializer.data)

    def update(self, request, *args, **kwargs):
        data = req_operate_by_user(request)
        partial = kwargs.pop('partial', False)
        instance = self.get_object()
        serializer = self.get_serializer(instance, data=data, partial=partial)
        serializer.is_valid(raise_exception=True)
        self.perform_update(serializer)

        if getattr(instance, '_prefetched_objects_cache', None):
            # If 'prefetch_related' has been applied to a queryset, we need to
            # forcibly invalidate the prefetch cache on the instance.
            instance._prefetched_objects_cache = {}

        return CCAIResponse(data="success")

    def destroy(self, request, *args, **kwargs):
        instance = self.get_object()
        self.perform_destroy(instance)
        return CCAIResponse(data="delete resource success")

    @action(methods=['delete'], detail=False)
    def multiple_delete(self, request, *args, **kwargs):
        try:
            delete_id = request.query_params.get('ids', None)
            if not delete_id:
                return CCAIResponse("参数不对啊！", NOT_FOUND)
            for i in delete_id.split(','):
                get_object_or_404(self.queryset, pk=int(i)).delete()
            return CCAIResponse("批量删除成功", OK)
        except Exception as e:
            error_logger.error("multiple delete crawler news failed:  \n%s" % traceback.format_exc())
            return CCAIResponse("批量删除失败", SERVER_ERROR)


def chacewang_exception_handler(exc, context):
    response = exception_handler(exc, context)
    if response is not None:
        msg = "失败" if response.status_code >= 400 else "成功"
        notification_response = {}
        notification_response["code"] = response.status_code
        notification_response["message"] = msg
        notification_response["detail"] = response.data
        response.data = notification_response
    return response


class CommonPagination(PageNumberPagination):
    """
    分页设置
    """
    # 默认每页显示的数据条数
    page_size = 10
    # 获取url参数中设置的每页显示数据条数
    page_size_query_param = settings.MY_PAGE_SIZE_QUERY_PARAM
    # 获取url中传入的页码key
    page_query_param = settings.MY_PAGE_QUERY_PARAM
    # 最大支持的每页显示的数据条数
    max_page_size = settings.MY_MAX_PAGE_SIZE

    """
    自定义分页方法
    """

    def get_paginated_response(self, data):
        """
        设置返回内容格式
        """
        return CCAIResponse(
            count=self.page.paginator.count,
            data=data)


class RbacPermission(BasePermission):
    """
    自定义权限
    """

    @classmethod
    def get_permission_from_role(self, request):
        try:
            perms = request.user.roles.values(
                "permissions__method",
            ).distinct()
            return [p["permissions__method"] for p in perms]
        except AttributeError:
            return None

    def has_permission(self, request, view):
        perms = self.get_permission_from_role(request)
        if perms:
            if "admin" in perms:
                return True
            elif not hasattr(view, "perms_map"):
                return True
            else:
                perms_map = view.perms_map
                _method = request._request.method.lower()
                for i in perms_map:
                    for method, alias in i.items():
                        if (_method == method or method == "*") and alias in perms:
                            return True


class ObjPermission(BasePermission):
    """
    密码管理对象级权限控制
    """

    def has_object_permission(self, request, view, obj):
        perms = RbacPermission.get_permission_from_role(request)
        if "admin" in perms:
            return True
        elif request.user.id == obj.uid_id:
            return True


class TreeSerializer(serializers.Serializer):
    id = serializers.IntegerField()
    label = serializers.CharField(max_length=20, source="name")
    pid = serializers.PrimaryKeyRelatedField(read_only=True)


class TreeAPIView(ListAPIView):
    """
    自定义树结构View
    """
    serializer_class = TreeSerializer
    authentication_classes = (JSONWebTokenAuthentication,)
    permission_classes = (IsAuthenticated,)

    def list(self, request, *args, **kwargs):
        queryset = self.filter_queryset(self.get_queryset())
        page = self.paginate_queryset(queryset)
        serializer = self.get_serializer(queryset, many=True)
        tree_dict = {}
        tree_data = []
        try:
            for item in serializer.data:
                tree_dict[item["id"]] = item
            for i in tree_dict:
                if tree_dict[i]["pid"]:
                    pid = tree_dict[i]["pid"]
                    parent = tree_dict[pid]
                    parent.setdefault("children", []).append(tree_dict[i])
                else:
                    tree_data.append(tree_dict[i])
            results = tree_data
        except KeyError:
            results = serializer.data
        if page is not None:
            return self.get_paginated_response(results)
        return CCAIResponse(results)


def req_operate_by_user(request):
    data = request.data.copy()
    if request.method == "POST":
        data['create_user'] = request.user.username
        data['create_id'] = request.user.id
        data['update_user'] = request.user.username
        data['update_id'] = request.user.id
    elif request.method == "PUT":
        data['update_user'] = request.user.username
        data['update_id'] = request.user.id
    return data


def sha1_encrypt(data):
    """
    使用sha1加密算法，返回str加密后的字符串
    """
    sha = hashlib.sha1(data.encode('utf-8'))
    encrypts = sha.hexdigest()
    return encrypts
